package physicsSimTest;

import java.awt.Color;
import java.awt.Graphics;
import java.util.HashMap;

public class Particle {

	int id;
	double x, y;
	private Vector actualVelocity;
	double percentVelocity;
	//private boolean collided = true;
	Color col;
	double radius;
	int depth = 0;

	public Particle() {

	}

	public Particle(int i, double xP, double yP, double xVi, double yVi,
			double rad) {
		id = i;
		x = xP;
		y = yP;
		actualVelocity = new Vector(xVi, yVi);
		radius = rad;

		int r = (int) (Math.random() * 100 + 1);
		int g = (int) (Math.random() * 100 + 1);
		int b = (int) (Math.random() * 100 + 1);
		Color ran = new Color(155 + r, 155 + g, 155 + b);
		col = ran;
	}

	public void paint(Graphics g) {
		g.setColor(col);
		g.fillOval((int) (x-radius), (int) (y-radius), (int) radius * 2, (int) radius * 2);
	}

	public void move(double d, HashMap<Integer, Particle> partMap) {
		//System.out.println(id+": ("+x+", "+y+")");
		/*for (Integer i : partMap.keySet()) {
			if (i != id) {
				if(Double.isNaN(Vector.getMagnitude(actualVelocity)))
					actualVelocity = Vector.copy(Vector.ZERO);
				///System.out.println(i);
				//System.out.println("before: "+this.getRemainingVelocity());
				if(this.collide(partMap.get(i), d)){
					if(depth<10){
						move(d, partMap);
						depth++;
					}
					else{
						depth = 0;
					}
					return;
				}
				//System.out.println("other: "+this.getRemainingVelocity());
			}
		}*/
		x += getRemainingVelocity().x * d;
		y += getRemainingVelocity().y * d;
		boolean wallBounce = false;
		//System.out.println("newcord: ("+x+", "+y+")");
		double percent = 0.95;
		if (x-radius < 0) {
			wallBounce=true;
			percent *= 1*(x-radius-getRemainingVelocity().x*d)/(-1*getRemainingVelocity().x*d);
			//reduceRemainingVelocity(percent);
			//System.out.println("A: "+percent);
			x = 0+radius;
			actualVelocity.x = -1 * actualVelocity.x;
		} 
		else if (x+radius > 1000) {
			wallBounce=true;
			 percent *= 1*(1000-(x +radius- getRemainingVelocity().x*d))/(getRemainingVelocity().x*d);
			//reduceRemainingVelocity(percent);
			//System.out.println("B: "+percent);
			x = 1000-radius;
			actualVelocity.x = -1 * actualVelocity.x;
		}
		if (y-radius < 0) {
			wallBounce=true;
			 percent *= 1*(y -radius - getRemainingVelocity().y*d)/(-1*getRemainingVelocity().y*d);
			//reduceRemainingVelocity(percent);
			//System.out.println("C: "+percent);
			y = 0+radius;
			actualVelocity.y = -1 * actualVelocity.y;
		} 
		else if (y+radius > 1000) {
			wallBounce=true;
			 percent *= 1*(1000-(y +radius - getRemainingVelocity().y*d))/(getRemainingVelocity().y*d);
			//System.out.println("D: "+percent);
			//reduceRemainingVelocity(percent);
			y = 1000-radius;
			actualVelocity.y = -1 * actualVelocity.y;
		}
		if(!wallBounce){
			reduceRemainingVelocity(0);
			return;
		}
		else{
			//System.out.println(percent);
			reduceRemainingVelocity(percent);
			if(percent>0.001)
				move(d, partMap);
		}
	}

	public void resetVelocity(){
		percentVelocity = 1;
		if(Vector.getMagnitude(actualVelocity)<0.001)
			actualVelocity = Vector.copy(Vector.ZERO);
	}


	public Collision collide(Particle other, double d) {
		
		if(Double.isNaN(Vector.getMagnitude(other.actualVelocity)))
			other.actualVelocity = Vector.copy(Vector.ZERO);
		if(Double.isNaN(Vector.getMagnitude(this.actualVelocity)))
			this.actualVelocity = Vector.copy(Vector.ZERO);
		
		// System.out.println("test1 "+this.id+" "+other.id);
		Vector otherV = other.getRemainingVelocity();

		Vector moveVec = Vector.subtract(
				Vector.scalarMultiply(d, getRemainingVelocity()),
				Vector.scalarMultiply(d, otherV));
		
		if(Vector.getMagnitude(moveVec)==0)
			return null;

		double dist = Math.sqrt((this.x - other.x) * (this.x - other.x)
				+ (this.y - other.y) * (this.y - other.y));
		dist -= (this.radius + other.getRadius());
		//System.out.println("dist"+dist);
		if (Vector.getMagnitude(moveVec) < dist)
			return null;
		// System.out.println("test2 "+this.id+" "+other.id);
		Vector posV = Vector.subtract( other.getPosVector(), this.getPosVector());
		//System.out.println(posV);
		//System.out.println("dot: "+Vector.dotProduct(Vector.normal(moveVec), posV));
		double D = Vector.dotProduct(Vector.normal(moveVec), posV);
		if (D < 0)
			return null;
		//System.out.println("test3 "+this.id+" "+other.id);

		double closeDist = Vector.getMagnitude(posV);

		double shortestDist = closeDist * closeDist - D*D;
		double sumRadiiSquared = Math.pow(this.radius + other.radius, 2);

		if (shortestDist >= sumRadiiSquared)
			return null;
		//System.out.println("test4 "+this.id+" "+other.id);

		double thirdSide = sumRadiiSquared - shortestDist;
		if (thirdSide < 0)
			return null;

		//System.out.println("test5 "+this.id+" "+other.id);

		double neededDist = D - Math.sqrt(thirdSide);
		double mag = Vector.getMagnitude(moveVec);
		if (mag < neededDist)
			return null;

		//System.out.println("collides "+this.id+" "+other.id+" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");

		// this.velocity = Vector.scalarMultiply(0, this.velocity);
		Vector neededV = Vector.normal(moveVec);
		neededV = Vector.scalarMultiply(neededDist, neededV);
		double tempPercent = Vector.getMagnitude(neededV)/Vector.getMagnitude(moveVec);
		if(Double.isNaN(tempPercent)){
			System.out.println(this.getPosVector());
			System.out.println();
			return null;
		}
		//System.out.println("TEMPPERCENTADSFADSFASDFASDFJALDSFJKASJDF: "+tempPercent);

		//this.actualVelocity = new Vector(0, 0);
		//other.actualVelocity = new Vector(0, 0);

		Collision c = new Collision(tempPercent, this, other, posV, d);
		
		
		return c;
	}

	void reduceRemainingVelocity(double percent) {
		percentVelocity*=percent;

	}

	void changeVelocityByActual(Vector newV) {
		actualVelocity = newV;
	}



	public Vector getRemainingVelocity() {
		return Vector.scalarMultiply(percentVelocity, actualVelocity);
	}

	public Vector getPosVector() {
		return new Vector(this.x, this.y);
	}

	public double getRadius() {
		return radius;
	}
	
	public double getMass(){
		return 1;
		//return getRadius();
	}
	
	public void accellerate(Vector a){
		actualVelocity = Vector.add(a, actualVelocity);
	}

	public void forceTo(Vector posVector, float magnitude) {
		double dist = Math.sqrt((this.x - posVector.x) * (this.x - posVector.x)
				+ (this.y - posVector.y) * (this.y - posVector.y));
		dist -= (this.radius*2);
		if(dist<this.radius/4)
			return;
		Vector posDiff = Vector.subtract(posVector, this.getPosVector());
		float actualMag = (float) (magnitude/Vector.getMagnitude(posDiff));
		posDiff = Vector.normal(posDiff);
		posDiff = Vector.scalarMultiply(actualMag, posDiff);
		accellerate(posDiff);
	}
	
	public void forceFromSquared(Vector posVector, float magnitude){
		Vector posDiff = Vector.subtract(posVector, this.getPosVector());
		float actualMag = (float) (magnitude/Math.pow(Vector.getMagnitude(posDiff),2));
		posDiff = Vector.normal(posDiff);
		posDiff = Vector.scalarMultiply(-1*actualMag, posDiff);
		accellerate(posDiff);
	}

	public void airResist(float delta) {
		Vector oppNormV = Vector.normal(Vector.scalarMultiply(-1, actualVelocity));
		oppNormV = Vector.scalarMultiply(delta*Vector.getMagnitude(actualVelocity)/25000.0, oppNormV);
		accellerate(oppNormV);
		//System.out.println("airresits: "+Vector.getMagnitude(oppNormV));
	}

	public Vector getActualVelocity() {
		return actualVelocity;
	}
	
	private double betterRoundDown(double d, int digits){
		double toReturn = d;
		toReturn*=Math.pow(10, digits);
		toReturn = (int)(toReturn);
		toReturn/=Math.pow(10, digits);
		return toReturn;
	}

	public void roundDownVelocity(int amount) {
		actualVelocity.x = betterRoundDown(actualVelocity.x, 10);
		actualVelocity.y = betterRoundDown(actualVelocity.y, 10);
		
	}

}
